package com.sinotn.ks.node.report;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.sinotn.SinotnLogger;
import com.sinotn.SinotnRuntime;
import com.sinotn.ks.definition.AbstractExamEvent;
import com.sinotn.ks.definition.ExamEngine;
import com.sinotn.ks.definition.Message;
import com.sinotn.ks.netty.MessageNotifier;
import com.sinotn.ks.netty.message.SimpleMessage;
import com.sinotn.ks.node.meta.service.ServerAuthService;
import com.sinotn.ks.node.meta.vo.ServerAuthVO;
import com.sinotn.ks.node.runtime.dao.cond.ExamItemCond;
import com.sinotn.ks.node.runtime.service.PlanService;
import com.sinotn.ks.node.runtime.service.RuntimeService;
import com.sinotn.ks.node.runtime.vo.ExamItemVO;
import com.sinotn.ks.node.runtime.vo.RoomExamRoundVO;
import com.sinotn.ks.thirdsys.api.platform.KsPlatform;
/**
 * 定时上报考生登录状态
 * @Title RuntimeReport.java
 * @Package com.sinotn.ks.node.report
 * @Description
 * Copyright: Copyright (c) 2015
 * Company:北京信诺软通
 *
 * @author <a href="mailto:xieqj@sinoth.com">谢启进</a>
 * @date 2020年8月17日 下午3:12:15
 * @version V1.0
 */
public class RuntimeReport extends AbstractExamEvent implements Runnable {
	@Autowired
	private ExamEngine examEngine;
	@Autowired
	private KsPlatform ksPlatform;
	@Autowired
	private ServerAuthService serverAuthSvr;
	@Autowired
	private PlanService planService;
	@Autowired
	private RuntimeService runtimeSvr;
	private int order=1;
	private boolean start=false;
	private int errCount=0;
	private long lazyMills=0;
	// 最大延时上报时间9分钟
	private long maxLazyMills=540000;
	// 默认一分钟上报时间间隔
	private long reportInterval=60000;
	private String planId=null;
	private String serverId=null;
	private Date roundBeginTime=null;
	private Date roundEndTime=null;
	private Date reportTime=null;
	private RandomAccessFile reportFile;

	public void setOrder(int order) {
		this.order = order;
	}

	public void setMaxLazyMills(long maxLazyMills) {
		this.maxLazyMills = maxLazyMills;
	}

	public void setReportInterval(long reportInterval) {
		this.reportInterval = reportInterval;
	}

	private void reset(){
		this.planId=null;
		this.serverId=null;
		this.roundBeginTime=null;
		this.roundEndTime=null;
	}

	private File getRptFile(){
		return new File(SinotnRuntime.getBinFolder(), "report.dt");
	}

	private void getReportTime(){
		try{
			if(this.reportFile==null){
				File file=getRptFile();
				if(file.exists()){
					this.reportFile=new RandomAccessFile(file, "rw");
				}
			}
			if(this.reportFile!=null){
				this.reportTime=new Date(this.reportFile.readLong());
			}
		}catch(Throwable e){
			SinotnLogger.DEBUG.error("读取最近成功上报时间发生系统错误", e);
		}
	}

	private void writeLastRptTime(long timestamp){
		try{
			if(this.reportFile==null){
				File file=getRptFile();
				this.reportFile=new RandomAccessFile(file, "rw");
			}
			this.reportFile.seek(0);
			this.reportFile.writeLong(timestamp);
		}catch(Throwable e){
			SinotnLogger.DEBUG.error("保存最近成功上报时间发生系统错误", e);
		}
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	@Override
	public boolean onExamineeLoad(Object evt) {
		if(examEngine.getRunState()==ExamEngine.STATE_STD){
			// 正式考试状态才启用
			if(this.ksPlatform.startReport()){
				if(!this.start){
					Thread thread=new Thread(this);
					thread.setDaemon(true);
					thread.setName("sinotnExamRpt");
					thread.start();
					this.start=true;
				}
			} else {
				Thread thread=new Thread(new Runnable() {
					@Override
					public void run() {
						try{
							Thread.sleep(120000);
							if(ksPlatform.startReport()){
								if(!start){
									Thread thread=new Thread(this);
									thread.setDaemon(true);
									thread.setName("sinotnExamRpt");
									thread.start();
									start=true;
								}
							}
						}catch(Throwable e){
							SinotnLogger.DEBUG.error("考试运行报告连接二次建立失败", e);
						}
					}
				});
				thread.start();
			}

		}
		return false;
	}

	@Override
	public boolean onRoundEnd(Object evt) {
		try{
			this.start=false;
			this.planId=null;
			this.roundBeginTime=null;
			this.roundEndTime=null;
			this.reportTime=null;
			if(this.reportFile!=null){
				IOUtils.closeQuietly(this.reportFile);
				this.reportFile=null;
			}
			this.ksPlatform.stopReport();
		}catch(Throwable e){
			SinotnLogger.DEBUG.error("考试结束收卷时关闭状态报告发生系统错误", e);
		}
		return false;
	}

	private void lazy(){
		// 发生一次错误，上报时间间隔增加一分钟
		this.lazyMills+=60000;
		if(this.lazyMills>this.maxLazyMills){
			this.lazyMills=this.maxLazyMills;
		}
	}

	private String getReportText(long lastTimestamp){
		ExamItemCond cond=new ExamItemCond();
		if(this.reportTime!=null){
			cond.setGtFirstLoginTime(this.reportTime);
		}
		cond.setLeFirstLoginTime(new Date(lastTimestamp));
		List<ExamItemVO> list=this.runtimeSvr.findExamItems(1, 0, cond);
		if(list==null || list.isEmpty()){
			return null;
		}
		StringBuilder sb=new StringBuilder();
		if(this.planId==null){
			ServerAuthVO serverAuth=this.serverAuthSvr.getServerAuth();
			this.planId=serverAuth.getPlanId();
			this.serverId=serverAuth.getServerId();
		}
		sb.append(this.planId);
		ExamItemVO itemVo;
		if(this.roundBeginTime==null){
			itemVo=list.get(0);
			RoomExamRoundVO roomRound=this.planService.getRoomExamRound(itemVo.getRoundId());
			this.roundBeginTime=roomRound.getBeginTime();
			this.roundEndTime=roomRound.getEndTime();
		}
		sb.append("#").append(this.roundBeginTime.getTime());
		sb.append("#").append(this.roundEndTime.getTime());
		int size=list.size();
		for(int i=0;i<size;i++){
			itemVo=list.get(i);
			sb.append("#").append(itemVo.getExamineeId());
			sb.append("#").append(itemVo.getFirstLoginTime().getTime());
		}
		if(sb.length()==0){
			return null;
		}else{
			return sb.toString();
		}
	}

	@Override
	public void run() {
		this.reset();
		this.getReportTime();
		MessageNotifier notifier;
		long lastTimestamp;
		String reportText;
		Message message;
		while(true){
			try{
				Thread.sleep(this.reportInterval+this.lazyMills);
				lastTimestamp=System.currentTimeMillis();
				reportText=this.getReportText(lastTimestamp);
				if(reportText!=null){
					SimpleMessage sm=new SimpleMessage();
					sm.setType(10001);
					sm.setText(reportText);
					notifier=this.ksPlatform.report(this.serverId, sm);
					if(notifier==null){
						// 网络未连通，未能发送
						this.lazy();
					}else{
						notifier.doWait(0, "发送运行状态");
						message=notifier.getResponse();
						if(message!=null && message.getType()==0){
							// 上报成功
							this.writeLastRptTime(lastTimestamp);
							this.reportTime=new Date(lastTimestamp);
							this.errCount=0;
							this.lazyMills=0;
						} else {
							this.errCount++;
							if(this.errCount>100){
								// 上报异常超过100次终止上报
								this.start=false;
							}
							this.lazy();
							SinotnLogger.DEBUG.error(message==null?"上报服务器运行状态数据超时":"上报服务器运行状态数据失败:"+message.getText());
						}
					}
				}
			}catch(Throwable e){
				this.errCount++;
				if(this.errCount>100){
					// 上报异常超过100次终止上报
					this.start=false;
				}
				this.lazy();
				SinotnLogger.DEBUG.error("上报服务器运行状态数据发生系统错误", e);
			}
			if(this.start==false){
				break;
			}
		}
	}
}
